Skip to content

Wire ARCH_AARCH64 into to_executable_fmt for exe and exe-only#21588

Merged
bwatters-r7 merged 3 commits into
rapid7:masterfrom
vinicius-batistella:fix/exe-aarch64-dispatch
Jul 8, 2026
Merged

Wire ARCH_AARCH64 into to_executable_fmt for exe and exe-only#21588
bwatters-r7 merged 3 commits into
rapid7:masterfrom
vinicius-batistella:fix/exe-aarch64-dispatch

Conversation

@vinicius-batistella

Copy link
Copy Markdown
Contributor

Wire ARCH_AARCH64 into to_executable_fmt for exe and exe-only formats

Summary

Msf::Util::EXE::ClassMethods#to_executable_fmt is missing ARCH_AARCH64
branches in its 'exe' and 'exe-only' cases. The helper
to_winaarch64pe (in lib/msf/util/exe/windows/aarch64.rb) is fully
implemented and the corresponding template
(data/templates/template_aarch64_windows.exe) ships with the
framework, but neither is reachable from msfvenom today because the
format dispatcher silently falls through when arch is AArch64 and
returns nil.

This means the existing windows/aarch64/exec payload — and any future
Windows AArch64 payload — cannot be wrapped into a PE via msfvenom:

$ ./msfvenom -p windows/aarch64/exec CMD=calc.exe -f exe -o exec.exe
[-] No platform was selected, choosing Msf::Module::Platform::Windows from the payload
[-] No arch selected, selecting arch: aarch64 from the payload
No encoder specified, outputting raw payload
Payload size: 360 bytes
Error: The payload could not be generated, check options

Fix

Add the missing when ARCH_AARCH64 branches to both 'exe' and
'exe-only' cases, dispatching to the already-existing
to_winaarch64pe helper:

when 'exe'
  case arch
  when ARCH_X86, nil
    to_win32pe(framework, code, exeopts)
  when ARCH_X64
    to_win64pe(framework, code, exeopts)
  when ARCH_AARCH64                         # <-- added
    to_winaarch64pe(framework, code, exeopts)
  end

Same two-line addition for 'exe-only'. No other code paths touched.

Verification

Before this PR:

$ ./msfvenom -p windows/aarch64/exec CMD=calc.exe -f exe -o exec.exe
Error: The payload could not be generated, check options

After this PR:

$ ./msfvenom -p windows/aarch64/exec CMD=calc.exe -f exe -o exec.exe
[*] Payload size: 360 bytes
[*] Final size of exe file: 6656 bytes
[*] Saved as: exec.exe

$ file exec.exe
exec.exe: PE32+ executable (console) Aarch64, for MS Windows

The resulting PE was executed on Windows 11 ARM64 (build 26200) and
correctly launched calc.exe.

-f raw, -f c, -f hex, and -f bin already worked because they do
not go through the EXE wrapper. This PR makes -f exe and -f exe-only
catch up to the same support level.

Test plan

  • ./msfvenom -p windows/aarch64/exec CMD=calc.exe -f exe -o exec.exe succeeds
  • file exec.exe reports a PE32+ AArch64 console executable
  • exec.exe runs and launches calc.exe on a Windows 11 ARM64 machine
  • ./msfvenom -p windows/aarch64/exec CMD=calc.exe -f exe-only -o exec_only.exe succeeds
  • Existing x86 and x64 -f exe / -f exe-only paths are unaffected (regression check)

to_executable_fmt's 'exe' and 'exe-only' cases were missing
ARCH_AARCH64 branches, so msfvenom could not wrap Windows AArch64
payloads (windows/aarch64/exec and future ones) into a PE despite
to_winaarch64pe and template_aarch64_windows.exe already existing.
Adds 2-line dispatch to to_winaarch64pe in both 'exe' and 'exe-only'.
@msutovsky-r7

Copy link
Copy Markdown
Contributor

This looks like it is same change as in #21589 - why do you need this PR?

@vinicius-batistella

Copy link
Copy Markdown
Contributor Author

@msutovsky-r7 — they're not duplicates, but I see why it looks that way. #21588 is a strict prerequisite for #21589, and #21589's branch is stacked on top of #21588's commit, so GitHub's diff for #21589 includes both changes (4-line exe.rb dispatch fix + the new ~380-line payload module).

#21588 stands on its own merit even ignoring #21589: windows/aarch64/exec already ships upstream, and to_winaarch64pe + template_aarch64_windows.exe are already in tree. Without the dispatcher fix, msfvenom -p windows/aarch64/exec -f exe returns "The payload could not be generated, check options" because to_executable_fmt's 'exe' / 'exe-only' cases silently fall through on ARCH_AARCH64. So the existing payload is broken under -f exe today and this 2-branch addition unbreaks it.

Happy to either:

  1. Retarget Add windows/aarch64/shell_reverse_tcp payload #21589's base from master to fix/exe-aarch64-dispatch so Add windows/aarch64/shell_reverse_tcp payload #21589's diff narrows to just the new payload module (and you merge Wire ARCH_AARCH64 into to_executable_fmt for exe and exe-only #21588 first, then Add windows/aarch64/shell_reverse_tcp payload #21589), or
  2. Land them in either order — the changes don't conflict, and git diff between the two branches will collapse cleanly once one is merged.

Whichever flow is least friction for you. Let me know.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR updates Metasploit’s executable format dispatcher (Msf::Util::EXE::ClassMethods#to_executable_fmt) so Windows AArch64 payloads can be wrapped as Windows executables via -f exe and -f exe-only, by routing ARCH_AARCH64 to the existing to_winaarch64pe helper.

Changes:

  • Add an ARCH_AARCH64 branch to the 'exe' format case, dispatching to to_winaarch64pe.
  • Add an ARCH_AARCH64 branch to the 'exe-only' format case (currently also dispatching to to_winaarch64pe).

Impact Analysis:

  • Blast radius: medium; affects msfvenom/framework consumers that generate Windows executables via to_executable_fmt, but only when arch == ARCH_AARCH64 and format is exe/exe-only.
  • Data and contract effects: changes output contract from nil to a generated PE for AArch64 in these formats; no schema/storage changes.
  • Rollback and test focus: easy rollback (single-file change); validate msfvenom -f exe and -f exe-only for AArch64 (including -x custom template behavior for exe-only) and ensure x86/x64 paths remain unchanged.

Comment thread lib/msf/util/exe.rb Outdated
Comment on lines +161 to +162
when ARCH_AARCH64
to_winaarch64pe(framework, code, exeopts)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 580d45f. Folded ARCH_X64 and ARCH_AARCH64 into one when branch since they make the same to_winpe_only(framework, code, exeopts, arch) call, matching the x64 path so -f exe-only -x <user.exe> injects via PE-section surgery instead of failing on the PAYLOAD: tag lookup.

vinicius-batistella and others added 2 commits June 25, 2026 19:33
to_winaarch64pe is the wrapper helper for the 'exe' format -- it
requires the default template_aarch64_windows.exe which contains
a literal PAYLOAD: placeholder, and aborts with "Invalid Windows
AArch64 template: missing \"PAYLOAD:\" tag" on any other PE.

That breaks the whole purpose of 'exe-only', which exists to
support user-supplied PE templates via msfvenom -x. The x64 path
correctly dispatches to to_winpe_only(framework, code, exeopts,
arch), which does PE-section surgery and works on arbitrary PEs.

Wire ARCH_AARCH64 through the same to_winpe_only call. Caught by
GitHub Copilot review.

Co-authored-by: Cursor <cursoragent@cursor.com>
Align to_winaarch64pe call with surrounding to_win32pe/to_win64pe
branches. Caught by GitHub Copilot review.

Co-authored-by: Cursor <cursoragent@cursor.com>
@bwatters-r7 bwatters-r7 self-assigned this Jul 7, 2026
@bwatters-r7

Copy link
Copy Markdown
Contributor

Before

msf payload(windows/aarch64/exec) > show options

Module options (payload/windows/aarch64/exec):

   Name      Current Setting  Required  Description
   ----      ---------------  --------  -----------
   CMD       calc.exe         yes       The command string to execute
   EXITFUNC  process          yes       Exit technique (Accepted: '', seh, thread, process, none)


View the full module info with the info, or info -d command.

msf payload(windows/aarch64/exec) > generate -f exe -o exe.exe
[-] Payload generation failed: Unsupported buffer format: exe
msf payload(windows/aarch64/exec) > 

After

msf payload(cmd/windows/smb/x64/meterpreter/reverse_tcp) > use payload/windows/aarch64/exec
msf payload(windows/aarch64/exec) > show options

Module options (payload/windows/aarch64/exec):

   Name      Current Setting  Required  Description
   ----      ---------------  --------  -----------
   CMD       calc.exe         yes       The command string to execute
   EXITFUNC  process          yes       Exit technique (Accepted: '', seh, thread, process, none)


View the full module info with the info, or info -d command.

msf payload(windows/aarch64/exec) > generate -f exe -o exe.exe
[*] Writing 6656 bytes to exe.exe...
image

@github-project-automation github-project-automation Bot moved this from Todo to In Progress in Metasploit Kanban Jul 8, 2026
@bwatters-r7 bwatters-r7 merged commit cdd2448 into rapid7:master Jul 8, 2026
18 checks passed
@github-project-automation github-project-automation Bot moved this from In Progress to Done in Metasploit Kanban Jul 8, 2026
@bwatters-r7

Copy link
Copy Markdown
Contributor

Release Notes

Fix a bug in the format dispatcher where although we can generate AARCH64 windows exe files, we fail trying to do so because the dispatcher does not properly handle the request by the user.

@bwatters-r7 bwatters-r7 added rn-fix release notes fix and removed rn-enhancement release notes enhancement labels Jul 8, 2026
@bwatters-r7

Copy link
Copy Markdown
Contributor

I removed the rn-enhancement and replaced it with rn-fix because this functionality existed, but we never added the dispatcher code. I felt that was an oversight on the feature addition before.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement rn-fix release notes fix

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

6 participants